package com.zb.util;

import java.lang.management.ManagementFactory;
import java.lang.management.RuntimeMXBean;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

import javax.annotation.PostConstruct;

import org.apache.log4j.Logger;
import org.apache.log4j.MDC;
import org.springframework.stereotype.Service;

import com.sun.management.OperatingSystemMXBean;

/**
 * author: zhengbo.zb
 */
@Service
public class JvmMonitor {
    private static Logger     logger                  = Logger.getLogger("DIGEST_LOG");
    private long              lastProcessCpuTime      = 0;
    private long              lastUptime              = 0;
    public static final int   DEFAULT_REFRESH_SECONDS = 60;

    @PostConstruct
    public void init() {
        logger.info("jvm monitor start  ...");
        ScheduledExecutorService executorService = Executors.newScheduledThreadPool(1);
        executorService.scheduleAtFixedRate(new Runnable() {
            @Override
            public void run() {
                record();
            }
        }, 1, DEFAULT_REFRESH_SECONDS, TimeUnit.SECONDS);
    }

    public void record() {
        long memory = getMemoryUsed();
        double cpu = getCpu();
        int threadCount = getThreadCount();
        MDC.put("memory", memory);
        MDC.put("cpu", cpu);
        MDC.put("threadCount", threadCount);
        double loadAverage = getLoadAverage();
        MDC.put("loadAverage", loadAverage);
        String message = "memoryUsed=" + memory + "m " + " cpuUsed=" + cpu + " threadCount="
                         + threadCount +" loadAverage="+loadAverage;


        logger.info(message);
        MDC.remove("loadAverage");
        MDC.remove("memory");
        MDC.remove("cpu");
        MDC.remove("threadCount");
    }

    protected int getThreadCount() {
        return ManagementFactory.getThreadMXBean().getThreadCount();
    }

    protected long getMemoryUsed() {
        return (Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory())
               / (1024 * 1024);
    }

    protected double getCpu() {
        OperatingSystemMXBean osbean = (OperatingSystemMXBean) ManagementFactory
            .getOperatingSystemMXBean();
        RuntimeMXBean runbean = ManagementFactory.getRuntimeMXBean();
        long uptime = runbean.getUptime();
        long processCpuTime = osbean.getProcessCpuTime();
        //cpu count
        int processors = osbean.getAvailableProcessors();
        //uptime in milliseconds ,and    processCpuTime in nao seconds
        double cpu = (processCpuTime - lastProcessCpuTime)
                     / ((uptime - lastUptime) * 10000f * processors);
        lastProcessCpuTime = processCpuTime;
        lastUptime = uptime;
        return (int) cpu; //
    }

    public static double getLoadAverage() {
        return ManagementFactory.getOperatingSystemMXBean().getSystemLoadAverage();
    }

    public static void main(String[] args) {
        double result = getLoadAverage();
        System.out.println(result);
    }
}
